Ships can still be used normally without installing modules, so mob ships don't need to be changed, however once a module has been installed on a ship (even if if it is then removed) that ship will need modules to work properly. The hull cannot be changed by modules.

If you do not define a ship's maxmodules a default of 10 will be set.

Currently a maximum of 99 modules can be installed because I can't be bothered making a linked list right now.

in space.c

in local routines

void	fread_modules			args	( ( SHIP_DATA *ship, FILE *fp ) );
void	update_ship_modules		args	( ( SHIP_DATA *ship ) );
bool	module_type_install		args	( ( OBJ_DATA *obj, SHIP_DATA *ship ) );


in save_ship

at start int module;

somewhere in the fprintf's

fprintf( fp, "MaxModules   %d\n",		ship->maxmodules    	);

after fprintf( fp, "End\n\n");
add
	if ( ship->modules > 0 )
	{
		fprintf( fp, "#MODS\n"					);
		for ( module = 1; module <= ship->modules; module++ )
		{
			fprintf( fp, "Vnum         %d\n", ship->module_vnum[module] );	
		}
		fprintf( fp, "End\n\n"					);
	}

in fread_ship

in CASE "E"

after 	ship->prev_in_room=NULL;
add

			ship->modules=0;
			if (ship->maxmodules == 0)
				ship->maxmodules = 10;
			


in CASE "M"
add
KEY( "MaxModules",		ship->maxmodules,	fread_number( fp ) );


in load_ship_file

after 
	    if ( !str_cmp( word, "SHIP"	) )
		{
			fread_ship( ship, fp );
			break;
		}

remove break from above listing and then add

	    else if ( !str_cmp( word, "MODS" ) )	
		{		
			/*log_string( "Read Modules" );*/
			fread_modules( ship, fp );
			/*log_string( "Use Modules" );*/
			update_ship_modules( ship );
		}

in do_setship add

if ( !str_cmp( arg2, "maxmodules" ) )
	{
		if (atoi(argument) < ship->modules)
		{
			send_to_char("You cannot lower the maxmodules below the current number of modules installed.\n\r",ch);
			return;
		}
		if (atoi(argument) > MAX_MODULES);
		{
			send_to_char("maxmodules currently limited to 99, because I am lazy.\n\r",ch);
			return;
		}
		ship->maxmodules = atoi(argument);
		return;
	}


in do_showship add

ch_printf( ch, "Modules: %d/%d\n\r", ship->modules, ship->maxmodules);

in do_makeship add after ship->target2=NULL;

ship->maxmodules=10;
ship->modules=0;

in do_launch add after ship->shipstate = SHIP_DOCKED;

			  if (ship->energy == 0)
			  {
				  send_to_char("&RThis ship has no fuel, try installing a fuel module.\n\r",ch);
				  return;
			  }	

/* This will mean that if a ship has no fuel module and it is hijacked then it will explode! */



at end:-

void fread_modules( SHIP_DATA *ship, FILE *fp )
{
	char * word;
	int	module;

	ship->modules = 0;

	for ( module=1; module<MAX_MODULES; module++ )
	{
		word   = feof( fp ) ? "End" : fread_word( fp );
		if ( !str_cmp( word, "End" ) )
			return;
		else
		{
			ship->module_vnum[module] = fread_number( fp );
			
			ship->modules += 1;
		}
		
	}
	return;

}

void update_ship_modules( SHIP_DATA *ship )
{
	AFFECT_DATA *paf;
	int	module;

	ship->hyperspeed = 0;
	ship->realspeed = 0;
	ship->maxshield = 0;
	ship->lasers = 0;
	ship->tractorbeam = 0;
	ship->maxmissiles = 0;
	ship->maxrockets = 0;
	ship->maxtorpedos = 0;
	ship->maxenergy = 0;
	ship->comm = 0;
	ship->sensor = 0;
	ship->astro_array = 0;
	ship->chaff = 0;
	ship->manuever = 0;

	for ( module=1; module<=ship->modules; module++ )
	{
		for ( paf = get_obj_index(ship->module_vnum[module])->first_affect; paf; paf = paf->next )
		{
			if ( paf->location == APPLY_HYPERSPEED)
				ship->hyperspeed += paf->modifier;
			if ( paf->location == APPLY_REALSPEED)
				ship->realspeed += paf->modifier;
			if ( paf->location == APPLY_MAXSHIELD)
				ship->maxshield += paf->modifier;
			if ( paf->location == APPLY_LASERS)
				ship->lasers += paf->modifier;
			if ( paf->location == APPLY_TRACTORBEAM)
				ship->tractorbeam += paf->modifier;
			if ( paf->location == APPLY_MAXMISSILES)
				ship->maxmissiles += paf->modifier;
			if ( paf->location == APPLY_MAXROCKETS)
				ship->maxrockets += paf->modifier;
			if ( paf->location == APPLY_MAXTORPEDOS)
				ship->maxtorpedos += paf->modifier;
			if ( paf->location == APPLY_MAXENERGY)
				ship->maxenergy += paf->modifier;
			if ( paf->location == APPLY_COMM)
			{
				if ( paf->modifier > ship->comm )							
					ship->comm = paf->modifier;
			}
			if ( paf->location == APPLY_SENSOR)
			{
				if ( paf->modifier > ship->sensor )			
					ship->sensor = paf->modifier;
			}
			if ( paf->location == APPLY_ASTRO_ARRAY)
			{
				if ( paf->modifier > ship->astro_array )
					ship->astro_array = paf->modifier;
			}
			if ( paf->location == APPLY_CHAFF)
				ship->chaff += paf->modifier;
			if ( paf->location == APPLY_MANUEVER)
				ship->manuever += paf->modifier;
		}
	}
	return;
}




void do_install_module( CHAR_DATA *ch, char *argument )
{

    char arg1[MAX_INPUT_LENGTH];
	char arg2[MAX_INPUT_LENGTH];
    OBJ_DATA *obj;
    SHIP_DATA *ship;
    

    argument = one_argument( argument, arg1 );
    argument = one_argument( argument, arg2 );

    if ( arg1[0] == '\0' )
    {
	send_to_char( "install what?\n\r", ch );
	return;
    }

    if ( arg2[0] == '\0' )
    {
	send_to_char( "in what?\n\r", ch );
	return;
    }

	ship = ship_in_room( ch->in_room , arg2 );    
    if ( !ship )            
	{    
		act( AT_PLAIN, "I see no $T here.", ch, NULL, argument, TO_CHAR );        
		return;       
    }

	if ( !check_pilot( ch , ship ) || !str_cmp( ship->owner , "Public" ) )    	        
	{    
		send_to_char("&RHey, thats not your ship!\n\r",ch);    	
		return;    	
	}

	if (ship->maxmodules == ship->modules )
	{
		send_to_char( "The ship has no free slots!\n\r", ch );
		return;
	}


    if ( ms_find_obj(ch) )
	return;

	if ( ( obj = get_obj_carry( ch, arg1 ) ) == NULL )
	{
	    send_to_char( "You do not have that item.\n\r", ch );
	    return;
	}


	if ( (!obj->item_type==ITEM_FIGHTERCOMP || obj->item_type==ITEM_MIDCOMP
		|| obj->item_type==ITEM_CAPITALCOMP) )
	{
		send_to_char("That isn't a ship module.\n\r",ch);
		return;
	}

	if ( obj->item_type==ITEM_FIGHTERCOMP && ship->class != FIGHTER_SHIP )
	{
		send_to_char( "That module is designed for a fighter.\n\r",ch);
		return;
	}

	if ( obj->item_type==ITEM_MIDCOMP && ship->class != MIDSIZE_SHIP )
	{
		send_to_char( "That module is designed for a midship.\n\r",ch);
		return;
	}

	if ( obj->item_type==ITEM_CAPITALCOMP && ship->class != CAPITAL_SHIP )
	{
		send_to_char( "That module is designed for a capital ship.\n\r",ch);
		return;
	}


	if ( !can_drop_obj( ch, obj ) )
	{
	    send_to_char( "You can't let go of it.\n\r", ch );
	    return;
	}

	if ( module_type_install(obj, ship) )
	{
		send_to_char( "Ships can only have one of those!\n\r", ch);
		return;
	}

	separate_obj( obj );

	act( AT_ACTION, "$n installs $p.", ch, obj, NULL, TO_ROOM );
	act( AT_ACTION, "You install $p.", ch, obj, NULL, TO_CHAR );

	ship->modules += 1;
	ship->module_vnum[ship->modules] = obj->pIndexData->vnum;
	extract_obj(obj);
	save_ship( ship );
	update_ship_modules( ship );
	  
    return;

}


bool module_type_install(OBJ_DATA *obj, SHIP_DATA *ship)
{
	int	module;
	AFFECT_DATA	*pafship;
	AFFECT_DATA *pafobj;


	for ( module=1; module<=ship->modules; module++ )
	{
		for ( pafship = get_obj_index(ship->module_vnum[module])->first_affect; pafship; pafship = pafship->next )
		{
			for ( pafobj = obj->pIndexData->first_affect; pafobj; pafobj = pafobj->next )
			{
				if ( pafship->location == pafobj->location &&
					( pafobj->location == APPLY_HYPERSPEED || pafobj->location == APPLY_REALSPEED
					|| pafobj->location == APPLY_MAXSHIELD || pafobj->location == APPLY_TRACTORBEAM ) )
					return TRUE;
			}
		}
	}
	return FALSE;
}


void do_remove_module( CHAR_DATA *ch, char *argument )
{

    char arg1[MAX_INPUT_LENGTH];
	char arg2[MAX_INPUT_LENGTH];
    OBJ_DATA *obj;
	OBJ_INDEX_DATA *obj_index;
    SHIP_DATA *ship;
	int	module, rmodule;


    argument = one_argument( argument, arg1 );
    argument = one_argument( argument, arg2 );

    if ( arg1[0] == '\0' )
    {
		send_to_char( "install what?\n\r", ch );
		return;
    }

    if ( arg2[0] == '\0' )
    {
		send_to_char( "in what?\n\r", ch );
		return;
    }

	ship = ship_in_room( ch->in_room , arg2 );    
    if ( !ship )            
	{    
		act( AT_PLAIN, "I see no $T here.", ch, NULL, argument, TO_CHAR );        
		return;       
    }

	if ( !check_pilot( ch , ship ) || !str_cmp( ship->owner , "Public" ) )    	        
	{    
		send_to_char("&RHey, thats not your ship!\n\r",ch);    	
		return;    	
	}

	for ( module = 1; module <= ship->modules; module++ )
	{
		obj_index=get_obj_index( ship->module_vnum[module] );
		if (!obj_index)
		{
			bug( "Remove module: cannot find module!\n\r", 0 );
			send_to_char("No such module installed\n\r",ch);
			return;
		}
		if ( nifty_is_name( arg1, obj_index->name ) )
		{
			obj = create_object( obj_index, 100 );
			act( AT_ACTION, "$n removes $p.", ch, obj, NULL, TO_ROOM );	
			act( AT_ACTION, "You remove $p.", ch, obj, NULL, TO_CHAR );
			obj = obj_to_char( obj, ch );
			
			for ( rmodule = module; rmodule < ship->modules; rmodule++ )			
			{				
				ship->module_vnum[rmodule] = ship->module_vnum[rmodule+1];			
			}
			ship->modules = ship->modules -1;

			update_ship_modules( ship );
			save_ship(ship);
			return;
		}
	}
	send_to_char("No such module installed\n\r",ch);
	return;
}

void do_show_modules( CHAR_DATA *ch, char *argument )
{

    char arg[MAX_INPUT_LENGTH];
	SHIP_DATA *ship;
	int	module;
	char buf[MAX_STRING_LENGTH];
	OBJ_INDEX_DATA *obj_index;

    argument = one_argument( argument, arg );

    if ( arg[0] == '\0' )
    {
		send_to_char( "check what ship?\n\r", ch );
		return;
    }

	ship = ship_in_room( ch->in_room , arg );    
    if ( !ship )            
	{    
		act( AT_PLAIN, "I see no $T here.", ch, NULL, argument, TO_CHAR );        
		return;       
    }
/*
	if ( !check_pilot( ch , ship ) || !str_cmp( ship->owner , "Public" ) )    	        
	{    
		send_to_char("&RHey, thats not your ship!\n\r",ch);    	
		return;    	
	}
*/
	
    sprintf( buf, "Modules installed on %s:\n\r\n\r", ship->name );
	send_to_char(buf,ch);
	if (ship->modules == 0)
	{
		send_to_char( "No Modules installed.\n\r",ch);
		return;
	}
	for ( module = 1; module <= ship->modules; module++ )
	{
		obj_index=get_obj_index( ship->module_vnum[module] );
		if (!obj_index)
		{
			bug( "Show module: cannot find module!\n\r", 0 );
			return;
		}
		sprintf(buf,"%s\n\r",obj_index->short_descr);
		send_to_char(buf,ch);
	}
	return;
}






in table.c

add for do_show_modules, do_install_module and do_remove_module




in mud.h

with other #define

#define MAX_MODULES	99


in ship_data

    int		module_vnum[MAX_MODULES];
    int		modules;
    int		maxmodules;



with declares

DECLARE_DO_FUN( do_install_module );
DECLARE_DO_FUN( do_remove_module );
DECLARE_DO_FUN( do_show_modules );

and add these in table.c as appropriate


with apply_types insert:

APPLY_HYPERSPEED, APPLY_REALSPEED, APPLY_LASERS, APPLY_MAXSHIELD, APPLY_MAXENERGY,
APPLY_MAXMISSILES, APPLY_MAXROCKETS, APPLY_MAXTORPEDOS, APPLY_TRACTORBEAM, APPLY_COMM,
APPLY_SENSOR, APPLY_ASTRO_ARRAY, APPLY_CHAFF, APPLY_MANUEVER, 


before MAX_APPLY_TYPE

with item_types add:

ITEM_FIGHTERCOMP, ITEM_MIDCOMP, ITEM_CAPITALCOMP

and change

#define MAX_ITEM_TYPE		     ITEM_CHEMICAL

to

#define MAX_ITEM_TYPE		     ITEM_CAPITALCOMP


in handler.c

in char *affect_loc_name( int location )

add

	case APPLY_HYPERSPEED:	return "hyperspeed";
	case APPLY_REALSPEED:	return "realspeed";
	case APPLY_LASERS:	return "lasers";
	case APPLY_MAXSHIELD:	return "maxshield";
	case APPLY_MAXENERGY:	return "maxenergy";
	case APPLY_MAXMISSILES:	return "missiles";
	case APPLY_MAXROCKETS:	return "rockets";
	case APPLY_MAXTORPEDOS:	return "torpedos";
	case APPLY_TRACTORBEAM:	return "tractorbeam";
	case APPLY_COMM:	return "comm";
	case APPLY_SENSOR:	return "sensor";
	case APPLY_ASTRO_ARRAY:	return "astro array";
	case APPLY_CHAFF:	return "chaff";
	case APPLY_MANUEVER:	return "manuever";


in build.c

in char *	const	o_types	[] =

add "fightercomp", "midcomp", "capitalcomp"

in char *	const	a_types	[] =

add 

, "hyperspeed", "realspeed", "lasers", "shield", "energy", "missiles", "rockets", "torpedos", "tractorbeam", "comm", "sensor", "astro_array", "chaff", "manuever"


in db.c

with other ITEM_

add

case ITEM_FIGHTERCOMP:
case ITEM_MIDCOMP:
case ITEM_CAPITALCOMP:


online

type

cedit install_module create do_install_module
cedit install_module level 1
cedit remove_module create do_remove_module
cedit remove_module level 1
cedit show_modules create do_show_modules
cedit show_modules level 1
cedit save

